<!DOCTYPE html>
<!-- saved from url=(0118)http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5 -->
<html lang="en" dir="ltr" class="client-js"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin</title>
<meta charset="UTF-8">
<meta name="generator" content="MediaWiki 1.19.2">
<link rel="shortcut icon" href="http://roguebasin.roguelikedevelopment.org/favicon.ico">
<link rel="search" type="application/opensearchdescription+xml" href="http://roguebasin.roguelikedevelopment.org/opensearch_desc.php" title="RogueBasin (en)">
<link rel="EditURI" type="application/rsd+xml" href="http://roguebasin.roguelikedevelopment.org/api.php?action=rsd">
<link rel="alternate" type="application/atom+xml" title="RogueBasin Atom feed" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges&feed=atom">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=mediawiki.legacy.commonPrint%2Cshared%7Cskins.monobook&only=styles&skin=monobook&*">
<!--[if IE 6]><link rel="stylesheet" href="/skins/monobook/IE60Fixes.css?303" media="screen" /><![endif]-->
<!--[if IE 7]><link rel="stylesheet" href="/skins/monobook/IE70Fixes.css?303" media="screen" /><![endif]--><style type="text/css" media="all">.js-messagebox{margin:1em 5%;padding:0.5em 2.5%;border:1px solid #ccc;background-color:#fcfcfc;font-size:0.8em}.js-messagebox .js-messagebox-group{margin:1px;padding:0.5em 2.5%;border-bottom:1px solid #ddd}.js-messagebox .js-messagebox-group:last-child{border-bottom:thin none transparent}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:8b08bdc91c52a9ffba396dccfb5b473c */


.mw-collapsible-toggle{float:right} li .mw-collapsible-toggle{float:none} .mw-collapsible-toggle-li{list-style:none}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:4250852ed2349a0d4d0fc6509a3e7d4c */
</style><meta name="ResourceLoaderDynamicStyles" content="">
<link rel="stylesheet" href="http://roguebasin.roguelikedevelopment.org/load.php?debug=false&lang=en&modules=site&only=styles&skin=monobook&*">
<style>a:lang(ar),a:lang(ckb),a:lang(fa),a:lang(kk-arab),a:lang(mzn),a:lang(ps),a:lang(ur){text-decoration:none}a.new,#quickbar a.new{color:#ba0000}

/* cache key: 133099-basin:resourceloader:filter:minify-css:7:c88e2bcd56513749bec09a7e29cb3ffa */
</style>

<script src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/load.php"></script><style type="text/css"></style><script src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/load(1).php"></script>
<script>if(window.mw){
mw.config.set({"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_5","wgTitle":"Complete Roguelike Tutorial, using python+libtcod, part 5","wgCurRevisionId":30348,"wgArticleId":3804,"wgIsArticle":true,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Developing"],"wgBreakFrames":false,"wgPageContentLanguage":"en","wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgRelevantPageName":"Complete_Roguelike_Tutorial,_using_python+libtcod,_part_5","wgRestrictionEdit":[],"wgRestrictionMove":[]});
}</script><script>if(window.mw){
mw.loader.implement("user.options",function($){mw.user.options.set({"ccmeonemails":0,"cols":80,"date":"default","diffonly":0,"disablemail":0,"disablesuggest":0,"editfont":"default","editondblclick":0,"editsection":1,"editsectiononrightclick":0,"enotifminoredits":0,"enotifrevealaddr":0,"enotifusertalkpages":1,"enotifwatchlistpages":0,"extendwatchlist":0,"externaldiff":0,"externaleditor":0,"fancysig":0,"forceeditsummary":0,"gender":"unknown","hideminor":0,"hidepatrolled":0,"highlightbroken":1,"imagesize":2,"justify":0,"math":1,"minordefault":0,"newpageshidepatrolled":0,"nocache":0,"noconvertlink":0,"norollbackdiff":0,"numberheadings":0,"previewonfirst":0,"previewontop":1,"quickbar":5,"rcdays":7,"rclimit":50,"rememberpassword":0,"rows":25,"searchlimit":20,"showhiddencats":0,"showjumplinks":1,"shownumberswatching":1,"showtoc":1,"showtoolbar":1,"skin":"monobook","stubthreshold":0,"thumbsize":2,"underline":2,"uselivepreview":0,"usenewrc":0,"watchcreations":0,"watchdefault":0,"watchdeletion":
0,"watchlistdays":3,"watchlisthideanons":0,"watchlisthidebots":0,"watchlisthideliu":0,"watchlisthideminor":0,"watchlisthideown":0,"watchlisthidepatrolled":0,"watchmoves":0,"wllimit":250,"variant":"en","language":"en","searchNs0":true,"searchNs1":false,"searchNs2":false,"searchNs3":false,"searchNs4":false,"searchNs5":false,"searchNs6":false,"searchNs7":false,"searchNs8":false,"searchNs9":false,"searchNs10":false,"searchNs11":false,"searchNs12":false,"searchNs13":false,"searchNs14":false,"searchNs15":false});;},{},{});mw.loader.implement("user.tokens",function($){mw.user.tokens.set({"editToken":"+\\","watchToken":false});;},{},{});

/* cache key: 133099-basin:resourceloader:filter:minify-js:7:74a832f2292f1f4d40d425d223444e78 */
}</script>
<script>if(window.mw){
mw.loader.load(["mediawiki.page.startup","mediawiki.legacy.wikibits","mediawiki.legacy.ajax"]);
}</script><script type="text/javascript" src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/load(2).php"></script>
<style type="text/css">/*<![CDATA[*/
.source-python {line-height: normal;}
.source-python li, .source-python pre {
	line-height: normal; border: 0px none white;
}
/**
 * GeSHi Dynamically Generated Stylesheet
 * --------------------------------------
 * Dynamically generated stylesheet for python
 * CSS class: source-python, CSS id: 
 * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann
 * (http://qbnz.com/highlighter/ and http://geshi.org/)
 * --------------------------------------
 */
.python.source-python .de1, .python.source-python .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.python.source-python  {font-family:monospace;}
.python.source-python .imp {font-weight: bold; color: red;}
.python.source-python li, .python.source-python .li1 {font-weight: normal; vertical-align:top;}
.python.source-python .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.python.source-python .li2 {font-weight: bold; vertical-align:top;}
.python.source-python .kw1 {color: #ff7700;font-weight:bold;}
.python.source-python .kw2 {color: #008000;}
.python.source-python .kw3 {color: #dc143c;}
.python.source-python .kw4 {color: #0000cd;}
.python.source-python .co1 {color: #808080; font-style: italic;}
.python.source-python .coMULTI {color: #808080; font-style: italic;}
.python.source-python .es0 {color: #000099; font-weight: bold;}
.python.source-python .br0 {color: black;}
.python.source-python .sy0 {color: #66cc66;}
.python.source-python .st0 {color: #483d8b;}
.python.source-python .nu0 {color: #ff4500;}
.python.source-python .me1 {color: black;}
.python.source-python .ln-xtra, .python.source-python li.ln-xtra, .python.source-python div.ln-xtra {background-color: #ffc;}
.python.source-python span.xtra { display:block; }

/*]]>*/
</style>
<style type="text/css">/*<![CDATA[*/
@import "/index.php?title=MediaWiki:Geshi.css&usemsgcache=yes&action=raw&ctype=text/css&smaxage=18000";
/*]]>*/
</style></head>
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-Complete_Roguelike_Tutorial_using_python_libtcod_part_5 skin-monobook action-view">
<div id="globalWrapper">
<div id="column-content"><div id="content"><div id="mw-js-message" class="js-messagebox" style="display: none;"></div>
	<a id="top"></a>
	<div id="siteNotice"><div id="localNotice" lang="en" dir="ltr"></div></div>
	<h1 id="firstHeading" class="firstHeading"><span dir="auto">Complete Roguelike Tutorial, using python+libtcod, part 5</span></h1>
	<div id="bodyContent" class="mw-body">
		<div id="siteSub">From RogueBasin</div>
		<div id="contentSub"></div>
		<div id="jump-to-nav" class="mw-jump">Jump to: <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#column-one">navigation</a>, <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#searchInput">search</a></div>
		<!-- start content -->
<div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr"><center><table border="0" cellpadding="10" cellspacing="0" style="background:#F0E68C"><tbody><tr><td><center>
<p>This is part of a series of tutorials; the main page can be found <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod" title="Complete Roguelike Tutorial, using python+libtcod">here</a>.
</p><p>The tutorial uses libctod version 1.5.1. If you prefer to use 1.5.0, you can find the old version <a rel="nofollow" class="external text" href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&oldid=29869">here</a>
</p>
</center></td></tr></tbody></table></center>
<table id="toc" class="toc"><tbody><tr><td><div id="toctitle"><h2>Contents</h2><span class="toctoggle">&nbsp;[<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#" class="internal" id="togglelink">hide</a>]&nbsp;</span></div>
<ul>
<li class="toclevel-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#Preparing_for_combat"><span class="tocnumber">1</span> <span class="toctext"><b>Preparing for combat</b></span></a>
<ul>
<li class="toclevel-2 tocsection-1"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#Populating_the_dungeon"><span class="tocnumber">1.1</span> <span class="toctext">Populating the dungeon</span></a></li>
<li class="toclevel-2 tocsection-2"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#Blocking_objects"><span class="tocnumber">1.2</span> <span class="toctext">Blocking objects</span></a></li>
<li class="toclevel-2 tocsection-3"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#Game_states"><span class="tocnumber">1.3</span> <span class="toctext">Game states</span></a></li>
<li class="toclevel-2 tocsection-4"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5#Fighting_orderly"><span class="tocnumber">1.4</span> <span class="toctext">Fighting orderly</span></a></li>
</ul>
</li>
</ul>
</td></tr></tbody></table>
<p><br>
</p>
<center><h1> <span class="mw-headline" id="Preparing_for_combat"><b>Preparing for combat</b></span></h1></center>
<p><br>
</p>
<h2> <span class="mw-headline" id="Populating_the_dungeon"> Populating the dungeon </span></h2>
<p>Can you feel that? It's the sense of anticipation in the air! That's right, from now on we won't rest until our game lets us smite some pitiful minions of evil, for great justice! It'll be a long journey, and the code will become more complicated, but there's no point in tip-toeing around it any more; it's a game and we want to play it. Some sections will be a bit of a drag, but if you survive that, the next part will be much more fun and rewarding.
</p><p>First, we must handle monster placement. While this may seem daunting, it's actually pretty simple, thanks to our generic object system! It only requires us to create a new object and append it to the objects list. Therefore, all we need to do is, for each room, create a few monsters in random positions. So we'll create a simple function to populate a room:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> place_objects<span class="br0">(</span>room<span class="br0">)</span>:
    <span class="co1">#choose random number of monsters</span>
    num_monsters = libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, MAX_ROOM_MONSTERS<span class="br0">)</span>
&nbsp;
    <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>num_monsters<span class="br0">)</span>:
        <span class="co1">#choose random spot for this monster</span>
        x = libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, room.<span class="me1">x1</span>, room.<span class="me1">x2</span><span class="br0">)</span>
        y = libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, room.<span class="me1">y1</span>, room.<span class="me1">y2</span><span class="br0">)</span>
&nbsp;
        <span class="kw1">if</span> libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">100</span><span class="br0">)</span> <span class="sy0">&lt;</span> <span class="nu0">80</span>:  <span class="co1">#80% chance of getting an orc</span>
            <span class="co1">#create an orc</span>
            monster = Object<span class="br0">(</span>x, y, <span class="st0">'o'</span>, libtcod.<span class="me1">desaturated_green</span><span class="br0">)</span>
        <span class="kw1">else</span>:
            <span class="co1">#create a troll</span>
            monster = Object<span class="br0">(</span>x, y, <span class="st0">'T'</span>, libtcod.<span class="me1">darker_green</span><span class="br0">)</span>
&nbsp;
        objects.<span class="me1">append</span><span class="br0">(</span>monster<span class="br0">)</span></pre></div></div></div>
<p><br>
The constant <i>MAX_ROOM_MONSTERS = 3</i> will be defined with the other constants so that it can be easily tweaked.
</p><p>I decided to create orcs and trolls, but you can choose anything else. In fact, you should change this function as much as you want! This is probably the simplest method. If you want to add more monsters, you'll need to keep the random value in a variable and compare it multiple times, using this pattern:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="co1">#chances: 20% monster A, 40% monster B, 10% monster C, 30% monster D:</span>
choice = libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">100</span><span class="br0">)</span>
<span class="kw1">if</span> choice <span class="sy0">&lt;</span> <span class="nu0">20</span>:
    <span class="co1">#create monster A</span>
<span class="kw1">elif</span> choice <span class="sy0">&lt;</span> <span class="nu0">20</span>+<span class="nu0">40</span>:
    <span class="co1">#create monster B</span>
<span class="kw1">elif</span> choice <span class="sy0">&lt;</span> <span class="nu0">20</span>+<span class="nu0">40</span>+<span class="nu0">10</span>:
    <span class="co1">#create monster C</span>
<span class="kw1">else</span>:
    <span class="co1">#create monster D</span></pre></div></div></div>
<p><br>
As an alternative, you could define a number of pre-set squads and choose one of them randomly, each squad being a combination of some monsters (for example, one troll and a few orcs, or 50% orcs and 50% goblin archers). The sky is the limit! You can also place items in the same manner, but we'll get to that later.
</p><p>Now, for the dungeon generator to place monsters in each room, call this function right after <i>create_room</i>, inside <i>make_map</i>:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            <span class="co1">#add some contents to this room, such as monsters</span>
            place_objects<span class="br0">(</span>new_room<span class="br0">)</span></pre></div></div></div>
<p><br>
There! I also removed the dummy NPC from the initial objects list (before the main loop): it won't be needed any more.
</p>
<h2> <span class="mw-headline" id="Blocking_objects"> Blocking objects </span></h2>
<p>Here, we'll add a few bits that are necessary before we can move on. First, blocking objects. We don't want more than one monster standing in the same tile, because only one will show up and the rest will be hidden! Some objects, especially items, don't block (it would be silly if you couldn't stand right next to a healing potion!), so each object will have an extra "blocks" property. We'll also take the opportunity to allow each object to have a name, which will be useful for game messages and the Graphical User Interface (GUI), which we'll go over later. Just add these two properties to the beginning of the <i>Object</i> 's <i>__init__</i> method:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span>, x, y, char, name, color, blocks=<span class="kw2">False</span><span class="br0">)</span>:
        <span class="kw2">self</span>.<span class="me1">name</span> = name
        <span class="kw2">self</span>.<span class="me1">blocks</span> = blocks</pre></div></div></div>
<p><br>
Now, we'll create a function that tests if a tile is blocked, whether due to a wall or an object blocking it. It's very simple, but it will be useful in a lot of places, and will save you a lot of headaches further down the line.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> is_blocked<span class="br0">(</span>x, y<span class="br0">)</span>:
    <span class="co1">#first test the map tile</span>
    <span class="kw1">if</span> <span class="kw2">map</span><span class="br0">[</span>x<span class="br0">]</span><span class="br0">[</span>y<span class="br0">]</span>.<span class="me1">blocked</span>:
        <span class="kw1">return</span> <span class="kw2">True</span>
&nbsp;
    <span class="co1">#now check for any blocking objects</span>
    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw1">if</span> <span class="kw2">object</span>.<span class="me1">blocks</span> <span class="kw1">and</span> <span class="kw2">object</span>.<span class="me1">x</span> == x <span class="kw1">and</span> <span class="kw2">object</span>.<span class="me1">y</span> == y:
            <span class="kw1">return</span> <span class="kw2">True</span>
&nbsp;
    <span class="kw1">return</span> <span class="kw2">False</span></pre></div></div></div>
<p><br>
OK, now it's time to give it some use! First of all, in the <i>Object</i> 's <i>move</i> method, change the <i>if</i> condition to:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="kw1">if</span> <span class="kw1">not</span> is_blocked<span class="br0">(</span><span class="kw2">self</span>.<span class="me1">x</span> + dx, <span class="kw2">self</span>.<span class="me1">y</span> + dy<span class="br0">)</span>:</pre></div></div></div>
<p><br>
Anyone, including the player,  can't move over a blocking object now! Next, in the <i>place_objects</i> function, we'll see if the tile is unblocked before placing a new monster:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="co1">#only place it if the tile is not blocked</span>
        <span class="kw1">if</span> <span class="kw1">not</span> is_blocked<span class="br0">(</span>x, y<span class="br0">)</span>:</pre></div></div></div>
<p><br>
Don't forget to indent the lines after that. This guarantees that monsters don't overlap! And since objects have two more properties, we need to define them whenever we create one, such as the line that creates the player object.  Replace the old object initialization code:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #FDECEC"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="co1">#create object representing the player</span>
player = Object<span class="br0">(</span>SCREEN_WIDTH/<span class="nu0">2</span>, SCREEN_HEIGHT/<span class="nu0">2</span>, <span class="st0">'@'</span>, libtcod.<span class="me1">white</span><span class="br0">)</span>
&nbsp;
<span class="co1">#create an NPC</span>
npc = Object<span class="br0">(</span>SCREEN_WIDTH/<span class="nu0">2</span> - <span class="nu0">5</span>, SCREEN_HEIGHT/<span class="nu0">2</span>, <span class="st0">'@'</span>, libtcod.<span class="me1">yellow</span><span class="br0">)</span>
&nbsp;
<span class="co1">#the list of objects with those two</span>
objects = <span class="br0">[</span>npc, player<span class="br0">]</span></pre></div></div></div>
<p><br>
With this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="co1">#create object representing the player</span>
player = Object<span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="st0">'@'</span>, <span class="st0">'player'</span>, libtcod.<span class="me1">white</span>, blocks=<span class="kw2">True</span><span class="br0">)</span>
&nbsp;
<span class="co1">#the list of objects starting with the player</span>
objects = <span class="br0">[</span>player<span class="br0">]</span></pre></div></div></div>
<p><br>
And update the code that creates the monsters:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            <span class="kw1">if</span> libtcod.<span class="me1">random_get_int</span><span class="br0">(</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="nu0">100</span><span class="br0">)</span> <span class="sy0">&lt;</span> <span class="nu0">80</span>:  <span class="co1">#80% chance of getting an orc</span>
                <span class="co1">#create an orc</span>
                monster = Object<span class="br0">(</span>x, y, <span class="st0">'o'</span>, <span class="st0">'orc'</span>, libtcod.<span class="me1">desaturated_green</span>,
                    blocks=<span class="kw2">True</span><span class="br0">)</span>
            <span class="kw1">else</span>:
                <span class="co1">#create a troll</span>
                monster = Object<span class="br0">(</span>x, y, <span class="st0">'T'</span>, <span class="st0">'troll'</span>, libtcod.<span class="me1">darker_green</span>,
                    blocks=<span class="kw2">True</span><span class="br0">)</span></pre></div></div></div>
<p><br>
If you added the optional room "numbers" in part 3, you'll need to update the code to include a name.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">&nbsp;
            room_no = Object<span class="br0">(</span>new_x, new_y, <span class="kw2">chr</span><span class="br0">(</span><span class="nu0">65</span>+num_rooms<span class="br0">)</span>, <span class="st0">'room number'</span>, libtcod.<span class="me1">white</span><span class="br0">)</span></pre></div></div></div>
<h2> <span class="mw-headline" id="Game_states"> Game states </span></h2>
<p>Last stop before we get to the actual combat system! Our input system has a fatal flaw: player actions (movement, combat) and other keys (fullscreen, other options) are handled the same way. We need to separate them. This way, if the player pauses or dies he can't move or fight, but can press other keys. We also want to know if the player's input means he finished his turn or not; changing to fullscreen shouldn't count as a turn. I know they're just simple details - but the game would be incredibly annoying without them! We only need two global variables, the game state and the player's last action (set before the main loop).
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">game_state = <span class="st0">'playing'</span>
player_action = <span class="kw2">None</span></pre></div></div></div>
<p><br>
Inside <i>handle_keys</i>, the movement/combat keys can only be used if the game state is "playing":
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="kw1">if</span> game_state == <span class="st0">'playing'</span>:
        <span class="co1">#movement keys</span></pre></div></div></div>
<p><br>
We'll also change the same function so it returns a string with the type of player action. Instead of returning <i>True</i> to exit the game, return a special string:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="kw1">return</span> <span class="st0">'exit'</span>  <span class="co1">#exit game</span></pre></div></div></div>
<p><br>
And testing for all the movement keys, if the player didn't press any, then he didn't take a turn, so return a special string in that case:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">        <span class="kw1">else</span>:
            <span class="kw1">return</span> <span class="st0">'didnt-take-turn'</span></pre></div></div></div>
<p><br>
After the call to <i>handle_keys</i> in the main loop, we can check for the special string 'exit' to exit the game. Later we'll do other stuff according to the <i>player_action</i> string.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            player_action = handle_keys<span class="br0">(</span><span class="br0">)</span>
            <span class="kw1">if</span> player_action == <span class="st0">'exit'</span>:
                <span class="kw1">break</span></pre></div></div></div>
<p><br>
</p>
<h2> <span class="mw-headline" id="Fighting_orderly"> Fighting orderly </span></h2>
<p>For the first part of the combat system we have to manage the player and monsters taking combat turns, as well as the player making an attack. To make it simple, the player takes his turn first, in <i>handle_keys</i>. If he took a turn, all the monsters take theirs. This goes after the <i>handle_keys</i> block in the main loop:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">    <span class="co1">#let monsters take their turn</span>
    <span class="kw1">if</span> game_state == <span class="st0">'playing'</span> <span class="kw1">and</span> player_action <span class="sy0">!</span>= <span class="st0">'didnt-take-turn'</span>:
        <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
            <span class="kw1">if</span> <span class="kw2">object</span> <span class="sy0">!</span>= player:
                <span class="kw1">print</span> <span class="st0">'The '</span> + <span class="kw2">object</span>.<span class="me1">name</span> + <span class="st0">' growls!'</span></pre></div></div></div>
<p><br>
That's just a debug message, in the next part we'll call an AI routine to move and attack. Now we'll take care of the player input. Since he can attack now, instead of calling <i>move</i> (inside <i>handle_keys</i>) like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            player.<span class="me1">move</span><span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span><span class="br0">)</span>
            fov_recompute = <span class="kw2">True</span></pre></div></div></div>
<p><br>
...we'll make a function called <i>player_move_or_attack</i> and replace all those 4 blocks with calls like this:
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1">            player_move_or_attack<span class="br0">(</span><span class="nu0">0</span>, -<span class="nu0">1</span><span class="br0">)</span></pre></div></div></div>
<p><br>
The function itself has a few lines of code but doesn't do anything extraordinary. It has to check if there's an object in the direction the player wants to move. If so, a debug message will be printed (this will later be replaced by an actual attack) If not, the player will just move there.
</p><p><br>
</p>
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><div dir="ltr" class="mw-geshi" style="text-align: left;"><div class="python source-python"><pre class="de1"><span class="kw1">def</span> player_move_or_attack<span class="br0">(</span>dx, dy<span class="br0">)</span>:
    <span class="kw1">global</span> fov_recompute
&nbsp;
    <span class="co1">#the coordinates the player is moving to/attacking</span>
    x = player.<span class="me1">x</span> + dx
    y = player.<span class="me1">y</span> + dy
&nbsp;
    <span class="co1">#try to find an attackable object there</span>
    target = <span class="kw2">None</span>
    <span class="kw1">for</span> <span class="kw2">object</span> <span class="kw1">in</span> objects:
        <span class="kw1">if</span> <span class="kw2">object</span>.<span class="me1">x</span> == x <span class="kw1">and</span> <span class="kw2">object</span>.<span class="me1">y</span> == y:
            target = <span class="kw2">object</span>
            <span class="kw1">break</span>
&nbsp;
    <span class="co1">#attack if target found, move otherwise</span>
    <span class="kw1">if</span> target <span class="kw1">is</span> <span class="kw1">not</span> <span class="kw2">None</span>:
        <span class="kw1">print</span> <span class="st0">'The '</span> + target.<span class="me1">name</span> + <span class="st0">' laughs at your puny efforts to attack him!'</span>
    <span class="kw1">else</span>:
        player.<span class="me1">move</span><span class="br0">(</span>dx, dy<span class="br0">)</span>
        fov_recompute = <span class="kw2">True</span></pre></div></div></div>
<p><br>
Alright, the code is ready to test! No damage is done yet but you can see the monsters taking their turns after you (notice when you switch to fullscreen it doesn't count as a turn, yay!), and you can bump into them to heroically but unsuccessfully try to destroy them!
</p><p><br>
The whole code so far is available <a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5_code" title="Complete Roguelike Tutorial, using python+libtcod, part 5 code">here</a>.
</p><p><br>
Guess what's next?
</p><p><br>
<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_6" title="Complete Roguelike Tutorial, using python+libtcod, part 6">Go on to the next part</a>.
</p>
<!-- 
NewPP limit report
Preprocessor node count: 219/1000000
Post-expand include size: 0/2097152 bytes
Template argument size: 0/2097152 bytes
Expensive parser function count: 0/100
-->

<!-- Saved in parser cache with key 133099-basin:pcache:idhash:3804-0!*!0!!en!*!* and timestamp 20131213184633 -->
</div><div class="printfooter">
Retrieved from "<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&oldid=30348">http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&amp;oldid=30348</a>"</div>
		<div id="catlinks" class="catlinks"><div id="mw-normal-catlinks" class="mw-normal-catlinks"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Categories" title="Special:Categories">Category</a>: <ul><li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Category:Developing" title="Category:Developing">Developing</a></li></ul></div></div>		<!-- end content -->
				<div class="visualClear"></div>
	</div>
</div></div>
<div id="column-one">
	<div id="p-cactions" class="portlet">
		<h5>Views</h5>
		<div class="pBody">
			<ul>
				<li id="ca-nstab-main" class="selected"><a href="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin.html" primary="1" context="subject" title="View the content page [alt-c]" accesskey="c">Page</a></li>
				<li id="ca-talk"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Talk:Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5" primary="1" context="talk" title="Discussion about the content page [alt-t]" accesskey="t">Discussion</a></li>
				<li id="ca-viewsource"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&action=edit" primary="1" title="This page is protected.
You can view its source [alt-e]" accesskey="e">View source</a></li>
				<li id="ca-history"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&action=history" rel="archives" title="Past revisions of this page [alt-h]" accesskey="h">History</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-personal">
		<h5>Personal tools</h5>
		<div class="pBody">
			<ul>
				<li id="pt-login"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:UserLogin&returnto=Complete+Roguelike+Tutorial%2C+using+python%2Blibtcod%2C+part+5" title="You are encouraged to log in; however, it is not mandatory [alt-o]" accesskey="o">Log in / create account</a></li>
			</ul>
		</div>
	</div>
	<div class="portlet" id="p-logo">
<a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" style="background-image: url(/skins/roguebasin/RogueBasin_logo.png);" title="Visit the main page"></a>
	</div>
	<div class="generated-sidebar portlet" id="p-navigation">
		<h5>Navigation</h5>
		<div class="pBody">
			<ul>
				<li id="n-mainpage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Main_Page" title="Visit the main page [alt-z]" accesskey="z">Main Page</a></li>
				<li id="n-portal"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Community_portal" title="About the project, what you can do, where to find things">Community portal</a></li>
				<li id="n-recentchanges"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChanges" title="A list of recent changes in the wiki [alt-r]" accesskey="r">Recent changes</a></li>
				<li id="n-randompage"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:Random" title="Load a random page [alt-x]" accesskey="x">Random page</a></li>
				<li id="n-help"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Help" title="The place to find out">Help</a></li>
			</ul>
		</div>
	</div>
	<div id="p-search" class="portlet">
		<h5><label for="searchInput">Search</label></h5>
		<div id="searchBody" class="pBody">
			<form action="http://roguebasin.roguelikedevelopment.org/index.php" id="searchform">
				<input type="hidden" name="title" value="Special:Search">
				<input type="search" name="search" title="Search RogueBasin [alt-f]" accesskey="f" id="searchInput">
				<input type="submit" name="go" value="Go" title="Go to a page with this exact name if exists" id="searchGoButton" class="searchButton">&nbsp;
				<input type="submit" name="fulltext" value="Search" title="Search the pages for this text" id="mw-searchButton" class="searchButton">
			</form>
		</div>
	</div>
	<div class="portlet" id="p-tb">
		<h5>Toolbox</h5>
		<div class="pBody">
			<ul>
				<li id="t-whatlinkshere"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:WhatLinksHere/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5" title="A list of all wiki pages that link here [alt-j]" accesskey="j">What links here</a></li>
				<li id="t-recentchangeslinked"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:RecentChangesLinked/Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5" title="Recent changes in pages linked from this page [alt-k]" accesskey="k">Related changes</a></li>
				<li id="t-specialpages"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Special:SpecialPages" title="A list of all special pages [alt-q]" accesskey="q">Special pages</a></li>
				<li><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&printable=yes" rel="alternate">Printable version</a></li>
				<li id="t-permalink"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_5&oldid=30348" title="Permanent link to this revision of the page">Permanent link</a></li>
			</ul>
		</div>
	</div>
</div><!-- end of the left (by default at least) column -->
<div class="visualClear"></div>
<div id="footer">
	<div id="f-poweredbyico">
		<a href="http://www.mediawiki.org/"><img src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" width="88" height="31"></a>
	</div>
	<ul id="f-list">
		<li id="lastmod"> This page was last modified on 26 November 2012, at 02:19.</li>
		<li id="viewcount">This page has been accessed 14,369 times.</li>
		<li id="privacy"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:Privacy_policy" title="RogueBasin:Privacy policy">Privacy policy</a></li>
		<li id="about"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:About" title="RogueBasin:About">About RogueBasin</a></li>
		<li id="disclaimer"><a href="http://roguebasin.roguelikedevelopment.org/index.php?title=RogueBasin:General_disclaimer" title="RogueBasin:General disclaimer">Disclaimers</a></li>
	</ul>
</div>
</div>
<script>if(window.mw){
mw.loader.load(["mediawiki.user","mediawiki.page.ready"], null, true);
}</script><script src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/load(3).php" type="text/javascript"></script>
<script src="./Complete Roguelike Tutorial, using python+libtcod, part 5 - RogueBasin_files/load(4).php"></script>
<!-- Served in 0.169 secs. --><autoscroll_cursor hidden=""></autoscroll_cursor></body></html>